package com.UnionPayCenter.account.service.impl;

import com.UnionPayCenter.account.annotation.PayService;
import com.UnionPayCenter.account.entity.Account;
import com.UnionPayCenter.account.entity.ChargeBill;
import com.UnionPayCenter.account.entity.dto.ChargeDTO;
import com.UnionPayCenter.account.entity.dto.PayDTO;
import com.UnionPayCenter.account.enums.AccountErrorCodeEnum;
import com.UnionPayCenter.account.enums.AccountTypeEnum;
import com.UnionPayCenter.account.enums.ChargeStatusEnum;
import com.UnionPayCenter.account.enums.PayChannelEnum;
import com.UnionPayCenter.account.manager.ChargeBillManager;
import com.UnionPayCenter.account.service.AccountService;
import com.UnionPayCenter.distribution.constants.DistributionConstants;
import com.UnionPayCenter.distribution.dto.DistributionShareDTO;
import com.UnionPayCenter.distribution.entity.DistributionTemplateDO;
import com.UnionPayCenter.distribution.manager.DistributionTemplateManager;
import com.UnionPayCenter.entity.ShopInfoEntity;
import com.UnionPayCenter.entity.dto.ChargeResponse;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 余额支付
 * 需要考虑多账户同时支付情况
 */
@PayService(value = "balancePayService", channel = PayChannelEnum.BALANCE_PAY)
public class BalancePayService implements com.UnionPayCenter.account.service.PayService {

    @Autowired
    private AccountService accountService;

    @Autowired
    private ChargeBillManager chargeBillManager;

    @Autowired
    private DistributionTemplateManager templateManager;

    @Override
    public void pay(PayDTO payDTO) {
        Integer actualAmount = payDTO.getAmount();
        Integer userId = payDTO.getUserId();
        Account account = accountService.getAccountByUserId(userId, AccountTypeEnum.CHARGE);
        // 优先使用余额账户支付, 如果余额不足, 先支付完再使用收益账户支付
        Integer balance = account.getBalance();
        if (balance >= actualAmount) {
            accountService.pay(account.getAccountId(), actualAmount);
            return;
        }

        DistributionShareDTO distributionShareDTO = new DistributionShareDTO();
        distributionShareDTO.setBId(Long.valueOf(payDTO.getShopId()));
        distributionShareDTO.setShopId(Long.valueOf(payDTO.getShopId()));
        DistributionTemplateDO distributionTemplateDO = templateManager.queryTemplate(distributionShareDTO);
        Long distributionAccountId = null;
        Integer distributionBalance = 0;
        Integer payedAmount = balance;
        if (distributionTemplateDO != null && DistributionConstants.TURE_STRING.equals(distributionTemplateDO.getFlag())) {
            Account distributionAccount = accountService.getAccountByUserId(userId, AccountTypeEnum.DISTRIBUTION_CHARGE);
            if (distributionAccount != null) {
                distributionBalance = distributionAccount.getBalance();
                if (distributionBalance != null && distributionBalance > 0) {
                    distributionAccountId = distributionAccount.getAccountId();
                    if ((distributionBalance + balance) >= actualAmount) {
                        accountService.pay(account.getAccountId(), balance);
                        accountService.pay(distributionAccount.getAccountId(), actualAmount - balance);
                        return;
                    } else {
                        payedAmount -= distributionBalance;
                    }
                }
            }
        }

        Account rewardsAccount = accountService.getAccountByUserId(userId, AccountTypeEnum.CASH_REWARDS);
        if (rewardsAccount == null) {
            AccountErrorCodeEnum.ACCOUNT_BALANCE.exception();
        }

        Integer rewardsBalance = rewardsAccount.getBalance();

        if ((rewardsBalance + balance + distributionBalance) < actualAmount) {
            AccountErrorCodeEnum.ACCOUNT_BALANCE.exception();
        }

        accountService.pay(account.getAccountId(), payedAmount);
        if (distributionAccountId != null) {
            accountService.pay(distributionAccountId, distributionBalance);
        }
        accountService.pay(rewardsAccount.getAccountId(), actualAmount - payedAmount);
    }

    @Override
    public ChargeResponse charge(ChargeBill chargeBill, ChargeDTO chargeDTO, ShopInfoEntity shopInfo) {
        chargeBill.setThirdSn(chargeDTO.getSn());
        chargeBill.setSn(chargeDTO.getSn());
        chargeBill.setState(ChargeStatusEnum.SUCCESS);
        chargeBillManager.saveChargeBill(chargeBill);
        if (chargeDTO.isChargeDirect()) {
            accountService.charge(chargeDTO.getAccountId(), chargeDTO.getAmount(), null);
        }

        return null;
    }
}
